package infra

import (
	"github.com/tietang/props/kvs"
)

// 应用程序启动管理器-用于管理所有程序启动加载启动的生命周期：初始化、安装、启动...
type BootApplication struct {
	conf           kvs.ConfigSource // 系统资源配置文件：config.ini实例
	starterContext StarterContext   // 基础资源上下文Map
}

// 构建应用程序启动管理器，完成将配置实例注册到基础资源上下文结构体里
func New(conf kvs.ConfigSource) *BootApplication {
	b := &BootApplication{conf: conf, starterContext: StarterContext{}}
	// 将配置实例注册到基础资源上下文结构体里，供infra/starer.go的Props()可以获取到这个kvs.ConfigSource
	b.starterContext[KeyProps] = conf
	return b
}

// 启动应用程序-管理所有启动的生命周期：初始化、安装、启动...
func (b *BootApplication) Start() {
	b.init()  // 1. 初始化所有的starter
	b.setup() // 2. 安装所有的starter
	b.start() // 3. 启动所有的starter
}

func (b *BootApplication) init() {
	// 所有启动器都会注册到此注册器里，注册器把所有的启动器都存储在切片里，所以在初始和注册启动时，就按照切片的顺序来逐一初始化和注册启动器
	for _, starter := range StarterRegister.AllStarters() {
		starter.Init(b.starterContext) // 按照启动器注册的顺序，对每一个启动器进行初始化
	}
}

func (b *BootApplication) setup() {
	for _, starter := range StarterRegister.AllStarters() {
		starter.Setup(b.starterContext)
	}
}

func (b *BootApplication) start() {
	// 所有启动器都会注册到此注册器里，注册器把所有的启动器都存储在切片里，所以在初始和注册启动时，就按照切片的顺序来逐一初始化和注册启动器
	for i, starter := range StarterRegister.AllStarters() {
		if starter.StartBlocking() {
			//如果是最后一个可阻塞的，直接启动并阻塞
			if i+1 == len(StarterRegister.AllStarters()) {
				starter.Start(b.starterContext)
			} else {
				//如果不是，使用goroutine来异步启动，防止阻塞后面starter
				go starter.Start(b.starterContext)
			}
		} else {
			starter.Start(b.starterContext)
		}
	}
}
